package cn.com.pdfdemo.pdfUtil;

import cn.com.pdfdemo.pdfUtil.Enums.ContextTypeEnums;
import cn.com.pdfdemo.pdfUtil.annotation.CellProperty;
import cn.com.pdfdemo.pdfUtil.entity.MyPdfEntity;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.color.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.border.Border;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Cell;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class PdfUtil {
    /**
     * 如果是 sringboot 项目，则jar需要使用如下代码获取字体文件路径
     * */
    public static PdfFont loadFont() throws IOException {
        // 获取字体文件的输入流
        InputStream fontStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("font/SimSun.ttf");
        if (fontStream == null) {
            throw new IOException("无法找到字体文件");
        }

        // 将输入流内容读入字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = fontStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }
        byte[] fontBytes = byteArrayOutputStream.toByteArray();
        // 通过字节数组创建字体
        return PdfFontFactory.createFont(fontBytes, PdfEncodings.IDENTITY_H, true);
    }

    /**
     * 如果是 tomcat 项目，则需要使用如下代码获取字体文件路径
     * */
    /*public static PdfFont loadFont() throws IOException {
        // 获取字体文件的全路径
        String fontPath = PdfUtil.class.getResource("/").getPath()+"font"+File.separator+"SimSun.ttf";
        if (fontPath == null) {
            throw new IOException("无法找到字体文件");
        }
        // 通过字节数组创建字体
        return PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
    }*/

    /**
     * 下载到指定目录
     * @param o 转pdf实体类，可接受实体类或List<实体类>
     * @param myPdfEntity pdf初始化参数
     * @param url 导出地址
     * */
    public static void downLoad(Object o, MyPdfEntity myPdfEntity, String url) throws Exception {
        //1、创建流对象
        File file = new File(url);
        if (file.exists()) {
            if (!file.delete()) {
                System.out.println("Failed to delete the existing file.");
                return;
            }
        }
        PdfWriter pdfWriter = new PdfWriter(file);

        //2、创建文档对象
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        //3、创建内容文档对象
        Document document = new Document(pdfDocument);
        PdfFont font = loadFont();
        // 1.4 创建内容
        if (myPdfEntity.getTitle() != null) {
            Paragraph paragraph = new Paragraph(myPdfEntity.getTitle());
            //1.5 设置字体，解决中文显示问题
            paragraph.setFont(font);
            paragraph.setTextAlignment(myPdfEntity.getTextAlignment());//居中
            document.add(paragraph);
        }

        List<Object> oList = new ArrayList<>();
        if (o instanceof List) {
            oList = (List<Object>) o;
        } else {
            oList.add(o);
        }

        for (Object obj : oList) {

            //设置表格每列宽度
            Table table = new Table(myPdfEntity.getTableWidth());
            //设置表格宽度百分比
            table.setWidthPercent(100);

            // 根据反射 获取object
            Class<?> clazz = obj.getClass();
            // 获取属性
            Field[] fields = clazz.getDeclaredFields();
            // 表格列表 放到form后面
            List<Table> tableList = new ArrayList<>();
            // 根据属性获取属性值
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                Object value = field.get(obj);
                // 获取字段上的注解
                CellProperty cellProperty = field.getAnnotation(CellProperty.class);

                if (cellProperty == null) {
                    continue;
                }
                //创建表头

                if (cellProperty.isHead()) {
                    //创建表格标题
                    Cell head = new Cell(cellProperty.rowspan(),cellProperty.colspan()); //单元格所占行列
                    // 设置单元格公共逻辑
                    buildHeadCell(head, value, font, cellProperty);
                    //加入表格
                    // 增加一个空行
                    table.addHeaderCell(new Cell(cellProperty.rowspan(),cellProperty.colspan())
                            .setBorder(Border.NO_BORDER).setHeight(30));
                    table.addHeaderCell(head);
                }else {
                    if (cellProperty.contextType() == ContextTypeEnums.TABLE) {
                        if (value == null) {
                            continue;
                        }
                        Table subTableHead = null;
                        if (cellProperty.isShowName()) {
                            subTableHead = new Table(myPdfEntity.getTableWidth());
                            Cell tableHeadNull = new Cell(cellProperty.rowspan(), cellProperty.colspan()).setBorder(Border.NO_BORDER);
                            Cell tableHead = new Cell(cellProperty.rowspan(), cellProperty.colspan())
                                    .add(new Paragraph(cellProperty.name())
                                            .setFont(font))
                                    .setFontSize(cellProperty.fontSize() + 2)
                                    .setBorder(Border.NO_BORDER)
                                    .setFontColor(new DeviceRgb(0, 0, 0));
                            // 增加一个空行
                            subTableHead.addHeaderCell(tableHeadNull);
                            subTableHead.addHeaderCell(tableHeadNull);
                            subTableHead.addHeaderCell(tableHead);
                        }
                        Table subTable = buildTableCell(field, value, font, cellProperty);
                        if (null != subTable) {
                            if (null != subTableHead) {
                                tableList.add(subTableHead);
                            }
                            tableList.add(subTable);
                        }
                    }else {
                        // 设置字段名
                        if (cellProperty.isShowName()) {
                            Cell nameCell = new Cell(cellProperty.namerowspan(), cellProperty.namecolspan()).
                                    add(new Paragraph(cellProperty.name() + "：").setFont(font)).setFontSize(cellProperty.fontSize() + 1);
                            if (!cellProperty.border()) {
                                nameCell.setBorder(Border.NO_BORDER);
                            }
                            table.addCell(nameCell);
                            // 设置字段值
                            Cell valueCell=new Cell(cellProperty.rowspan(),cellProperty.colspan());
                            // 设置单元格公共逻辑
                            buildFormCell(valueCell, value, font, cellProperty);
                            table.addCell(valueCell);
                        }
                    }
                }
            }

            //输出表格
            document.add(table);
            for (Table tb : tableList) {
                document.add(tb);
            }
        }

        document.close();
        System.out.println("pdf生成完成!");

    }

    /**
     * 下载到本地
     * @param o 转pdf实体类，可接受实体类或List<实体类>
     * @param myPdfEntity pdf初始化参数
     * */
    public static void down(Object o, MyPdfEntity myPdfEntity, HttpServletResponse response) throws Exception {
        // 1 初始化
        OutputStream os = response.getOutputStream();
        //1.1 创建流对象
        PdfWriter pdfWriter=new PdfWriter(os);
        // 1.2 创建文档对象
        PdfDocument pdfDocument=new PdfDocument(pdfWriter);
        // 1.3 创建内容文档对象
        Document document=new Document(pdfDocument);
        PdfFont font = loadFont();
        // 1.4 创建内容
        if (myPdfEntity.getTitle() != null) {
            Paragraph paragraph=new Paragraph(myPdfEntity.getTitle());
            //1.5 设置字体，解决中文显示问题
            paragraph.setFont(font);
            paragraph.setTextAlignment(myPdfEntity.getTextAlignment());//居中
            document.add(paragraph);
        }

        List<Object> oList = new ArrayList<>();
        if (o instanceof List) {
            oList = (List<Object>) o;
        } else {
            oList.add(o);
        }

        for (Object obj : oList) {

            //设置表格每列宽度
            Table table = new Table(myPdfEntity.getTableWidth());
            //设置表格宽度百分比
            table.setWidthPercent(100);

            // 根据反射 获取object
            Class<?> clazz = obj.getClass();
            // 获取属性
            Field[] fields = clazz.getDeclaredFields();
            // 表格列表 放到form后面
            List<Table> tableList = new ArrayList<>();
            // 根据属性获取属性值
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                Object value = field.get(obj);
                // 获取字段上的注解
                CellProperty cellProperty = field.getAnnotation(CellProperty.class);

                if (cellProperty == null) {
                    continue;
                }
                //创建表头

                if (cellProperty.isHead()) {
                    //创建表格标题
                    Cell head = new Cell(cellProperty.rowspan(),cellProperty.colspan()); //单元格所占行列
                    // 设置单元格公共逻辑
                    buildHeadCell(head, value, font, cellProperty);
                    //加入表格
                    // 增加一个空行
                    table.addHeaderCell(new Cell(cellProperty.rowspan(),cellProperty.colspan())
                            .setBorder(Border.NO_BORDER).setHeight(30));
                    table.addHeaderCell(head);
                }else {
                    if (cellProperty.contextType() == ContextTypeEnums.TABLE) {
                        if (value == null) {
                            continue;
                        }
                        Table subTableHead = null;
                        if (cellProperty.isShowName()) {
                            subTableHead = new Table(myPdfEntity.getTableWidth());
                            Cell tableHeadNull = new Cell(cellProperty.rowspan(), cellProperty.colspan()).setBorder(Border.NO_BORDER);
                            Cell tableHead = new Cell(cellProperty.rowspan(), cellProperty.colspan())
                                    .add(new Paragraph(cellProperty.name())
                                            .setFont(font))
                                    .setFontSize(cellProperty.fontSize() + 2)
                                    .setBorder(Border.NO_BORDER)
                                    .setFontColor(new DeviceRgb(0, 0, 0));
                            // 增加一个空行
                            subTableHead.addHeaderCell(tableHeadNull);
                            subTableHead.addHeaderCell(tableHeadNull);
                            subTableHead.addHeaderCell(tableHead);
                        }
                        Table subTable = buildTableCell(field, value, font, cellProperty);
                        if (null != subTable) {
                            if (null != subTableHead) {
                                tableList.add(subTableHead);
                            }
                            tableList.add(subTable);
                        }
                    }else {
                        // 设置字段名
                        if (cellProperty.isShowName()) {
                            Cell nameCell = new Cell(cellProperty.namerowspan(), cellProperty.namecolspan()).
                                    add(new Paragraph(cellProperty.name() + "：").setFont(font)).setFontSize(cellProperty.fontSize() + 1);
                            if (!cellProperty.border()) {
                                nameCell.setBorder(Border.NO_BORDER);
                            }
                            table.addCell(nameCell);
                            // 设置字段值
                            Cell valueCell=new Cell(cellProperty.rowspan(),cellProperty.colspan());
                            // 设置单元格公共逻辑
                            buildFormCell(valueCell, value, font, cellProperty);
                            table.addCell(valueCell);
                        }
                    }
                }
            }

            //输出表格
            document.add(table);
            for (Table tb : tableList) {
                document.add(tb);
            }
        }


        // 设置响应头信息
        response.setContentType("application/pdf");
        String fileName = myPdfEntity.getFileName();
        if (fileName == null) {
            long currentTimeNanos = System.nanoTime();
            UUID uuid = UUID.randomUUID();
            fileName = currentTimeNanos + "_" + uuid.toString();
        }
        String encodedFileName = URLEncoder.encode(fileName + ".pdf", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
        // 关闭文档，此时PDF内容已写入到HttpServletResponse的OutputStream
        document.close();
        os.close();

        System.out.println("pdf生成完成!");

    }

    // 设置表头公共逻辑
    public static void buildHeadCell(Cell cell, Object value, PdfFont font, CellProperty cellProperty) throws IOException {
        cell.add(new Paragraph(String.valueOf(value == null ? "" : value)));
        // 设置字体
        cell.setFont(font);
        cell.setFontSize(cellProperty.fontSize() + 1);
        cell.setFontColor(new DeviceRgb(0, 0, 0));
        if (!cellProperty.border()) {
            cell.setBorderLeft(Border.NO_BORDER).setBorderRight(Border.NO_BORDER).setBorderBottom(Border.NO_BORDER);
        }
        // 设置居中方式
        cell.setTextAlignment(cellProperty.textAlignment());
    }

    // 设置表单公共逻辑
    public static void buildFormCell(Cell cell, Object value, PdfFont font, CellProperty cellProperty) throws IOException {

        if (ContextTypeEnums.IMAGE.equals(cellProperty.contextType())) {    //是否图片
            Image image=new Image(ImageDataFactory.create((byte[]) value));
            //设置图片缩放比例 水平 垂直
            //image.scale(0.5f,0.5f);
            float scaledWidth = cellProperty.scaledWidth(); // 设置宽度(毫米)
            float scaledHeight = cellProperty.scaledHeight(); // 设置高度(毫米)
            image.scaleToFit(scaledWidth, scaledHeight);
            cell.add(image);
        }if (ContextTypeEnums.TABLE.equals(cellProperty.contextType())) {    //是否表格

        } else if (cellProperty.showType()) {   //是否换行显示
            String [] split = String.valueOf(value).split(cellProperty.separator());
            for (String s : split) {
                cell.add(new Paragraph(s));
            }
        }else { // 普通文本内容
            cell.add(new Paragraph(String.valueOf(value == null ? "" : value)));
        }
        // 设置字体
        cell.setFont(font);
        cell.setFontSize(cellProperty.fontSize());
        cell.setFontColor(new DeviceRgb(79, 79, 79));
        if (!cellProperty.border()) {
            cell.setBorder(Border.NO_BORDER);
        }
        // 设置居中方式
        cell.setTextAlignment(cellProperty.textAlignment());
    }

    // 设置表格公共逻辑
    public static Table buildTableCell(Field field, Object value, PdfFont font, CellProperty cellProperty) throws IOException {

        // 获取子类
        Type genericType = field.getGenericType();
        Class<?> itemClass = null;
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            if (actualTypeArguments.length > 0) {
                Type itemClassType = actualTypeArguments[0];
                itemClass = (Class<?>) itemClassType;
                // 将子类构造为table
                System.out.println("Type of Item: " + itemClass.getName());
            }
        }
        // 获取子类上所有有CellProperty注解的属性
        List<Float> tableWidths = new ArrayList<>();
        Field[] subFields = itemClass.getDeclaredFields();
        for (Field subField : subFields) {
            if (subField.isAnnotationPresent(CellProperty.class)) {
                tableWidths.add(subField.getAnnotation(CellProperty.class).tableColWidth());
            }
        }
        if(tableWidths.size() == 0) {
            return null;
        }
        // 设置table标题
        //设置表格每列宽度
        float[] tableWidth = new float[tableWidths.size()];
        for (int i = 0; i < tableWidths.size(); i++) {
            tableWidth[i] = tableWidths.get(i);
        }
        Table subTable = new Table(tableWidth);
        //设置表格宽度百分比
        subTable.setWidthPercent(100);
        // 构造表头
        for (Field subField : subFields) {
            if (subField.isAnnotationPresent(CellProperty.class)) {
                System.out.println("Field Name: " + subField.getName());
                // 设置字段为可访问
                subField.setAccessible(true);
                // 设置表头
                Cell cell =new Cell(1, 1);
                cell.add(subField.getAnnotation(CellProperty.class).name());
                // 设置字体
                cell.setFont(font);
                cell.setFontSize(cellProperty.fontSize());
                // 设置居中方式
                cell.setTextAlignment(cellProperty.textAlignment());
                if (!cellProperty.border()) {
                    cell.setBorder(Border.NO_BORDER);
                }
                subTable.addCell(cell);
            }
        }

        // 构造内容
        List<?> listValue = (List<?>) value ;
        for (Object element : listValue) {
            // 获取子类上所有有 CellProperty 注解的属性
            for (Field subField : subFields) {
                if (subField.isAnnotationPresent(CellProperty.class)) {
                    System.out.println("Field Name: " + subField.getName());
                    // 设置字段为可访问
                    subField.setAccessible(true);
                    // 获取并打印属性值
                    try {
                        // 设置内容
                        Object fieldValue = subField.get(element);
                        Cell cell =new Cell(1, 1);
                        cell.add(fieldValue == null ? "" : fieldValue.toString());
                        // 设置字体
                        cell.setFont(font);
                        cell.setFontSize(cellProperty.fontSize());
                        cell.setFontColor(new DeviceRgb(79, 79, 79));
                        // 设置居中方式
                        cell.setTextAlignment(cellProperty.textAlignment());
                        if (!cellProperty.border()) {
                            cell.setBorder(Border.NO_BORDER);
                        }
                        subTable.addCell(cell);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException("Failed to access field value", e);
                    }
                }
            }
        }
        return subTable;
    }
}